#include "pch.hpp"
#include "Module.hpp"
#include "BinaryStream.hpp"

#include <boostext/iostreams/device/vector.hpp>

using namespace Engine;
using namespace Engine::Script;




Module::Module(asIScriptModule* module)
	: m_module(module)
{
	verify(m_module != nullptr);

	reflect();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Module::post_create(ptr _this)
{
	m_this = _this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

Module::~Module()
{}
///////////////////////////////////////////////////////////////////////////////////////////////////




std::vector<char> Module::bytecode() const
{
	std::vector<char> bytecode;
	boost::iostreams::stream<boostext::iostreams::vector> stream(bytecode);
	BinaryStream bstream(stream);

	m_module->SaveByteCode(&bstream);

	return bytecode;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




int Module::functionIdByDecl(const char* decl) const
{
	int ret = m_module->GetFunctionIdByDecl(decl);
	verify(ret >= 0);
	return ret;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

int Module::typeCount() const
{
	return m_types.size();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

bool Module::hasType(int id) const
{
	return m_types.find(id) != m_types.end();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

const Type& Module::type(int id) const
{
	auto it = m_types.find(id);
	if(it == m_types.end())
		throw invalid_value_exception(id);
	else
		return it->second;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

Function Module::function(int id) const
{
	auto handle = pointer<asIScriptFunction>(m_module->GetFunctionDescriptorById(id));
	return Function(m_this, handle);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

std::vector<Type> Module::types() const
{
	std::vector<Type> types;
	types.reserve(m_types.size());
	foreach(const auto& pair, m_types)
		types.push_back(pair.second);
	return types;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Module::reflect()
{
	// Fetch all new types
	int count = m_module->GetObjectTypeCount();
	for(int i = 0; i < count; ++i)
	{
		auto type = pointer<asIObjectType>(m_module->GetObjectTypeByIndex(i));
		int id = type->GetTypeId();

		m_types.insert(std::make_pair(id, Type(m_this, type)));
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
